package ar.uba.fi.tonyvaliente.signature;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;

import ar.uba.fi.tonyvaliente.documents.DocumentHashing;

public class HashTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		signatureTest();
//		allHashFunctionTest();
		
	}


	public static void allHashFunctionTest() {
		// String key = "abcdefghijklmnopqrstuvwxyz1234567890";
				Set<Number> numeroshf1 = new TreeSet<Number>();
				Set<Number> numeroshf2 = new TreeSet<Number>();
				Set<Number> numeroshf3 = new TreeSet<Number>();
				Set<Number> numeroshf4 = new TreeSet<Number>();
				Set<Number> numeroshf5 = new TreeSet<Number>();
				
				Set<String> palabras = new TreeSet<String>();
		
				HashFunction hf1 = new SqrAndHalf(Integer.MAX_VALUE);
				HashFunction hf2 = new MD5HashFunction(Integer.MAX_VALUE);
				HashFunction hf3 = new JSHash(Integer.MAX_VALUE);
				HashFunction hf4 = new FoldAndAddHashFunction(Integer.MAX_VALUE);
				HashFunction hf5 = new BKDRHashFunction(Integer.MAX_VALUE);
				
				String key;
				
				ByteArrayOutputStream baos = new ByteArrayOutputStream();
				
				Date inicio = new Date();
				for (int j = 0; j < 1000000; j++) {
		//			System.out.println("generando clave " + j);
					Random r = new Random();
					byte[] character = new byte[2];
					
					try {
						for (int i = 0; i < 5; i++) {
							r.nextBytes(character);
				
								baos.write(character);
							
						}
						baos.flush();
					} catch (IOException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
					
					key = new String(baos.toByteArray());
					baos.reset();
					
					palabras.add(key);
					try {
						Number sahHashValue = hf1.hash(key);
						numeroshf1.add(sahHashValue);
						Number MD5HashValue = hf2.hash(key);
						numeroshf2.add(MD5HashValue);
						Number JSHashValue = hf3.hash(key);
						numeroshf3.add(JSHashValue);
						Number faaHashValue = hf4.hash(key);
						numeroshf4.add(faaHashValue);
						Number BKDRHashValue = hf5.hash(key);
						numeroshf5.add(BKDRHashValue);
						
					} catch (HashFunctionException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				Date fin = new Date();
				
				Long duracion = fin.getTime() - inicio.getTime();
		
				System.out.println("duracion: " + duracion); 
				System.out.println("cantidad de key distintas: " + palabras.size());
				System.out.println("cantidad de hash distintos (Square & Half): " + numeroshf1.size());
				System.out.println("cantidad de hash distintos (MD5): " + numeroshf2.size());
				System.out.println("cantidad de hash distintos (JSHash): " + numeroshf3.size());
				System.out.println("cantidad de hash distintos (Fold & Add): " + numeroshf4.size());
				System.out.println("cantidad de hash distintos (BKDRHash): " + numeroshf5.size());
	}

	
	public static void signatureTest(){
		int length = Short.MAX_VALUE;
		System.out.println("document signature length: " + length);
		List<HashFunction> hashFunctions = new ArrayList<HashFunction>();
		hashFunctions.add(new MD5HashFunction(length));
		hashFunctions.add(new BKDRHashFunction(length));
		hashFunctions.add(new FoldAndAddHashFunction(length));
		hashFunctions.add(new JSHash(length));
		hashFunctions.add(new SqrAndHalf(length));
		List<String> filteredText = new ArrayList<String>(10000);

		DocumentHashing documentHashing = new DocumentHashing();
//		int documentId = documentHashing.addDocument(documentHash, title);
		
		String key;

		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		for (int k = 0; k < 1000; k++) {
			System.out.println(k);
//			try {
//				Thread.sleep(1000);
//			} catch (InterruptedException e1) {
//				// TODO Auto-generated catch block
//				e1.printStackTrace();
//			}
			filteredText.clear();
			for (int j = 0; j < 10000; j++) {
				Random r = new Random();
				byte[] character = new byte[2];
				
				try {
					for (int i = 0; i < 5; i++) {
						r.nextBytes(character);
			
						baos.write(character);
						
					}
					baos.flush();
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				
				key = new String(baos.toByteArray());
				baos.reset();
				
				filteredText.add(key);
			}
			
			List<BitSet> wordSignatures = new ArrayList<BitSet>(filteredText.size());
//			try {
//				Thread.sleep(1000);
//			} catch (InterruptedException e1) {
//				// TODO Auto-generated catch block
//				e1.printStackTrace();
//			}
			try {
				for (String word : filteredText) {
	//				List<Number> posiciones = new ArrayList<Number>();
					BitSet wordSignature = new BitSet(length);
					for (HashFunction hashFunction : hashFunctions) {
						// TODO si siempre vamos a castear a int mejor dejar que el método devuelva int y listo
						// sobre todo si el bitSet no soporta muchos bits.
						// Si se necesitan más bits hay que buscar una alternativa al bitSet
						Integer hashValue =  hashFunction.hash(word).intValue();
						
						wordSignature.set(hashValue, true);
						wordSignatures.add(wordSignature);
					}
					
				}
				
				BitSet signature = new BitSet(length);
				for (BitSet wordSignature : wordSignatures) {
					signature.or(wordSignature);
				}
//				System.out.println("document signature: " + signature);
			} catch (HashFunctionException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
		}
	}
}
